home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / NCSA / tn3270 2.4d7 source / tn3270 / telnet.c < prev    next >
Text File  |  1992-04-17  |  22KB  |  844 lines

  1. /*
  2.  *  tn3270 for the Macintosh Source Code
  3.  *  Brown University Computing and Information Services
  4.  *  Version 2.4d7  April, 1992
  5.  *  Copyright (c) 1988, 1989, 1990, 1991, 1992 by Brown University and by
  6.  *  Peter John DiCamillo.
  7.  *
  8.  *  Permission is granted to any individual or institution to use, copy,
  9.  *  or redistribute the binary version of this software and its
  10.  *  documentation provided this notice and the copyright notices are
  11.  *  retained.  Permission is granted to any individual or non-profit
  12.  *  institution to use, copy, modify, or redistribute the source files
  13.  *  of this software provided this notice and the copyright notices are
  14.  *  retained.  This software may not be distributed for profit, either
  15.  *  in original form or in derivative works, nor can the source be
  16.  *  distributed to other than an individual or a non-profit institution.
  17.  *  Any  individual or group interested in seeing and/or using these
  18.  *  source files but who are prevented from doing so by the above
  19.  *  constraints should contact Don Wolfe, Assistant Vice-President for
  20.  *  Computer Systems at Brown University, (401) 863-7250, for possible
  21.  *  software licensing of the source developed at Brown.
  22.  *
  23.  *  Brown University and Peter John DiCamillo make no representations
  24.  *  about the suitability of this software for any purpose.
  25.  *
  26.  *  BROWN UNIVERSITY AND PETER JOHN DICAMILLO GIVE NO WARRANTY, EITHER
  27.  *  EXPRESS OR IMPLIED, FOR THE PROGRAM AND/OR DOCUMENTATION PROVIDED,
  28.  *  INCLUDING, WITHOUT LIMITATION, WARRANTY OF MERCHANTABILITY AND
  29.  *  WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
  30.  *  -----------------------------------------------------------------------
  31.  *  The following copyright notice applies to the code in this file for
  32.  *  interpreting the Telnet protocol and performing option negotiations:
  33.  *  -----------------------------------------------------------------------
  34.  *    Copyright (c) 1984-1987 by the Regents of the
  35.  *    University of California and by Gregory Glenn Minshall.
  36.  *
  37.  *    Permission to use, copy, modify, and distribute these
  38.  *    programs and their documentation for any purpose and
  39.  *    without fee is hereby granted, provided that this
  40.  *    copyright and permission appear on all copies and
  41.  *    supporting documentation, the name of the Regents of
  42.  *    the University of California not be used in advertising
  43.  *    or publicity pertaining to distribution of the programs
  44.  *    without specific prior permission, and notice be given in
  45.  *    supporting documentation that copying and distribution is
  46.  *    by permission of the Regents of the University of California
  47.  *    and by Gregory Glenn Minshall.  Neither the Regents of the
  48.  *    University of California nor Gregory Glenn Minshall make
  49.  *    representations about the suitability of this software
  50.  *    for any purpose.  It is provided "as is" without
  51.  *    express or implied warranty.
  52.  */ 
  53.  
  54. #if !defined(USEDUMP)
  55.     #include "maclib.h"
  56.     #include "termdef.h"
  57.     #include "tn3270funcs.h"
  58.     #include "globals.h"
  59. #else
  60.     #pragma load "tn3270DumpFile"
  61. #endif
  62.  
  63. #define TELCMDS 1
  64. #define TELOPTS 1
  65. #include "telnet.h"
  66.  
  67. #pragma segment 3270tcp
  68.  
  69. /*
  70.  * Telnet receiver states for fsm
  71.  */
  72. #define    TS_DATA        0
  73. #define    TS_IAC        1
  74. #define    TS_WILL        2
  75. #define    TS_WONT        3
  76. #define    TS_DO        4
  77. #define    TS_DONT        5
  78. /*    #define    TS_CR        6       currently not used */
  79. #define    TS_SB        7        /* sub-option collection */
  80. #define    TS_SE        8        /* looking for sub-option end */
  81.  
  82. static unsigned char doopt[] = { IAC, DO, '%', 'c', 0 };
  83. static unsigned char dont[] = { IAC, DONT, '%', 'c', 0 };
  84. static unsigned char will[] = { IAC, WILL, '%', 'c', 0 };
  85. static unsigned char wont[] = { IAC, WONT, '%', 'c', 0 };
  86.  
  87. #define    SB_CLEAR()    cp->subpointer = cp->subbuffer;
  88. #define    SB_TERM()    cp->subend = cp->subpointer;
  89. #define    SB_ACCUM(c)    if (cp->subpointer < (cp->subbuffer+sizeof(cp->subbuffer))) { \
  90.                 *(cp->subpointer)++ = (c); \
  91.             }
  92.  
  93. static unsigned char sb_terminal[] = { IAC, SB,
  94.             TELOPT_TTYPE, TELQUAL_IS,
  95.             'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
  96.             IAC, SE };
  97. static unsigned char sb_e_terminal[] = { IAC, SB,
  98.             TELOPT_TTYPE, TELQUAL_IS,
  99.             'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
  100.             '-', 'E',
  101.             IAC, SE };
  102. #define SBTERMTYPE  11
  103. #define    SBTERMMODEL    13
  104.  
  105. void telrcv(register unsigned char *sbp,
  106.             register short scc,
  107.             cnr *cp)
  108. {
  109. register unsigned char c;
  110. register unsigned char *Sbp;
  111. register short Scc;
  112. short endflg, skipcnt;
  113.  
  114. if (scc <= 0) return;
  115.  
  116. if (cf_dblevel > 2) dbgdump("telrcv", sbp, scc);
  117.  
  118. cp->replyptr = cp->replybuff;
  119.  
  120. while (scc > 0) {
  121.     /*    if (cf_dblevel > 2) {
  122.             sprintf(dbgmsg, "scc = %d", scc);
  123.             putln(dbgmsg);
  124.             }    */
  125.     c = *sbp++;
  126.     scc--;
  127.     switch (cp->telrcv_state) {
  128.         case TS_DATA:
  129.             if (c == IAC) {
  130.                 cp->telrcv_state = TS_IAC;
  131.                 continue;
  132.                 }
  133.             Sbp = sbp;
  134.             Scc = scc;
  135.             skipcnt = 0;
  136.             while (Scc > 0) {
  137.                 c = *Sbp++;
  138.                 Scc--;
  139.                 if (c == IAC) {
  140.                     skipcnt++;
  141.                     cp->telrcv_state = TS_IAC;
  142.                     break;
  143.                     }
  144.                 }
  145.             endflg = 0;
  146.             if ((cp->telrcv_state == TS_IAC) && (Scc > 0))
  147.                 if ((*Sbp) == EOR) {
  148.                     skipcnt++;
  149.                     endflg = 1;
  150.                     Sbp++;
  151.                     Scc--;
  152.                     cp->telrcv_state = TS_DATA;
  153.                     }
  154.             tcpdata(sbp-1, scc+1-Scc-skipcnt, cp->data_init, endflg, cp);
  155.             cp->data_init = endflg;
  156.             sbp = Sbp;
  157.             scc = Scc;
  158.             break;
  159.  
  160.         case TS_IAC:
  161.             switch (c) {
  162.                 case WILL:
  163.                     cp->telrcv_state = TS_WILL;
  164.                     continue;
  165.                 case WONT:
  166.                     cp->telrcv_state = TS_WONT;
  167.                     continue;
  168.                 case DO:
  169.                     cp->telrcv_state = TS_DO;
  170.                     continue;
  171.                 case DONT:
  172.                     cp->telrcv_state = TS_DONT;
  173.                     continue;
  174.                 case DM:
  175.                     /*
  176.                      * We may have missed an urgent notification,
  177.                      * so make sure we flush whatever is in the
  178.                      * buffer currently.
  179.                      */
  180.                 /*    SYNCHing = 1;
  181.                     ttyflush();
  182.                     SYNCHing = stilloob(net);
  183.                     settimer(gotDM);            */
  184.                     break;
  185.                 case NOP:
  186.                 case GA:
  187.                     break;
  188.                 case SB:
  189.                     SB_CLEAR();
  190.                     cp->telrcv_state = TS_SB;
  191.                     continue;
  192.                 case EOR:
  193.                     tcpdata(0L, 0, cp->data_init, 1, cp);
  194.                     cp->data_init = 1;
  195.                     break;
  196.                 case IAC:
  197.                     tcpdata(sbp-1, 1, cp->data_init, 0, cp);
  198.                     cp->data_init = 0;
  199.                     break;
  200.                 default:
  201.                     break;
  202.                 }
  203.             cp->telrcv_state = TS_DATA;
  204.             continue;
  205.  
  206.         case TS_WILL:
  207.             printoption(">RCVD", will, c, !(cp->hisopts)[c]);
  208.             /* if (c == TELOPT_TM) {
  209.                 if (flushout) {
  210.                     flushout = 0;
  211.                     }
  212.                 }
  213.             else  */ if (!(cp->hisopts)[c]) {
  214.                     willoption(c, 1, cp);
  215.                     }
  216.             SetIn3270(cp);
  217.             cp->telrcv_state = TS_DATA;
  218.             continue;
  219.  
  220.         case TS_WONT:
  221.             printoption(">RCVD", wont, c, (cp->hisopts)[c]);
  222.             /* if (c == TELOPT_TM) {
  223.                 if (flushout) {
  224.                     flushout = 0;
  225.                     }
  226.                 }
  227.             else */  if ((cp->hisopts)[c]) {
  228.                 wontoption(c, 1, cp);
  229.                 }
  230.             SetIn3270(cp);
  231.             cp->telrcv_state = TS_DATA;
  232.             continue;
  233.  
  234.         case TS_DO:
  235.             printoption(">RCVD", doopt, c, !(cp->myopts)[c]);
  236.             if (!(cp->myopts)[c])
  237.             dooption(c, cp);
  238.             SetIn3270(cp);
  239.             cp->telrcv_state = TS_DATA;
  240.             continue;
  241.  
  242.         case TS_DONT:
  243.             printoption(">RCVD", dont, c, (cp->myopts)[c]);
  244.             if ((cp->myopts)[c]) {
  245.                 (cp->myopts)[c] = 0;
  246.                 sprintf(cp->replyptr, wont, c);
  247.                 cp->replyptr += sizeof (wont) - 2;
  248.                 /* flushline = 1; */
  249.                 /* setconnmode();     set new tty mode (maybe) */
  250.                 printoption(">SENT", wont, c, 0);
  251.                 }
  252.             SetIn3270(cp);
  253.             cp->telrcv_state = TS_DATA;
  254.             continue;
  255.  
  256.         case TS_SB:
  257.             if (c == IAC) {
  258.                 cp->telrcv_state = TS_SE;
  259.                 }
  260.             else {
  261.                 SB_ACCUM(c);
  262.                 }
  263.             continue;
  264.  
  265.         case TS_SE:
  266.             if (c != SE) {
  267.                 if (c != IAC) {
  268.                     SB_ACCUM(IAC);
  269.                     }
  270.                 SB_ACCUM(c);
  271.                 cp->telrcv_state = TS_SB;
  272.                 }
  273.             else {
  274.                 SB_TERM();
  275.                 suboption(cp);    /* handle sub-option */
  276.                 SetIn3270(cp);
  277.                 cp->telrcv_state = TS_DATA;
  278.                 }
  279.             continue;
  280.  
  281.         default:
  282.             break;
  283.         }
  284.     }
  285. if (cp->quitflg) {
  286.     cp->quitflg = 0;
  287.     return;
  288.     }
  289. if (cp->replyptr != cp->replybuff) {
  290.     tcpwrite(cp->replybuff, cp->replyptr-cp->replybuff, cp);
  291.         /* sends data, or ends connection if unable to send */
  292.     }
  293. }
  294.  
  295. /*VARARGS*/
  296. void printoption(unsigned char *direction, unsigned char *fmt,
  297.                  short option, short what)
  298. {
  299.     if (!cf_dblevel) return;
  300.     sprintf(dbgmsg, "%s ", direction+1);
  301.     putln(dbgmsg);
  302.     if (fmt == doopt)
  303.         fmt = "do";
  304.     else if (fmt == dont)
  305.         fmt = "dont";
  306.     else if (fmt == will)
  307.         fmt = "will";
  308.     else if (fmt == wont)
  309.         fmt = "wont";
  310.     else
  311.         fmt = "???";
  312.     if (option < (sizeof(telopts)/sizeof( telopts[0])))
  313.         sprintf(dbgmsg, "%s %s", fmt, telopts[option]);
  314.     else
  315.         sprintf(dbgmsg, "%s %d", fmt, option);
  316.     putln(dbgmsg);
  317.     if (*direction == '<') {
  318.         putln("\n");
  319.         return;
  320.     }
  321.     sprintf(dbgmsg, " (%s)\n", what ? "reply" : "don't reply");
  322.     putln(dbgmsg);
  323. }
  324.  
  325. void willoption(short option, short reply, cnr *cp)
  326. {
  327.     unsigned char *fmt;
  328.  
  329.     switch (option) {
  330.  
  331.     case TELOPT_ECHO:
  332.         /*
  333.          * The following is a pain in the rear-end.
  334.          * Various IBM servers (some versions of Wiscnet,
  335.          * possibly Fibronics/Spartacus, and who knows who
  336.          * else) will NOT allow us to send "DO SGA" too early
  337.          * in the setup proceedings.  On the other hand,
  338.          * 4.2 servers (telnetd) won't set SGA correctly.
  339.          * So, we are stuck.  Empirically (but, based on
  340.          * a VERY small sample), the IBM servers don't send
  341.          * out anything about ECHO, so we postpone our sending
  342.          * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
  343.          * DO send).
  344.          */
  345.         {
  346.         if (cp->askedSGA == 0) {
  347.             cp->askedSGA = 1;
  348.             if (!(cp->hisopts)[TELOPT_SGA]) {
  349.             willoption(TELOPT_SGA, 0, cp);
  350.             }
  351.         }
  352.         }
  353.         /* Fall through */
  354.     case TELOPT_EOR:
  355.     case TELOPT_BINARY:
  356.     case TELOPT_SGA:
  357.     case TELOPT_3270:
  358.         /* settimer(modenegotiated); */
  359.         (cp->hisopts)[option] = 1;
  360.         fmt = doopt;
  361.         /* setconnmode();        possibly set new tty mode */
  362.         break;
  363.  
  364.     case TELOPT_TM:
  365.         return;            /* Never reply to TM will's/wont's */
  366.  
  367.     default:
  368.         fmt = dont;
  369.         break;
  370.     }
  371.     sprintf(cp->replyptr, fmt, option);
  372.     cp->replyptr += sizeof (dont) - 2;
  373.     if (reply)
  374.         printoption(">SENT", fmt, option, reply);
  375.     else
  376.         printoption("<SENT", fmt, option, reply);
  377. }
  378.  
  379. void wontoption(short option, short reply, cnr *cp)
  380. {
  381.     unsigned char *fmt;
  382.  
  383.     switch (option) {
  384.  
  385.      case TELOPT_BINARY:        /* added for Mac tn3270 */
  386.     case TELOPT_ECHO:
  387.     case TELOPT_SGA:
  388.     case TELOPT_3270:
  389.         /* settimer(modenegotiated); */
  390.         (cp->hisopts)[option] = 0;
  391.         fmt = dont;
  392.         /* setconnmode();             Set new tty mode */
  393.         break;
  394.  
  395.     case TELOPT_TM:
  396.         return;        /* Never reply to TM will's/wont's */
  397.  
  398.     default:
  399.         fmt = dont;
  400.     }
  401.     sprintf(cp->replyptr, fmt, option);
  402.     cp->replyptr += sizeof (doopt) - 2;
  403.     if (reply)
  404.         printoption(">SENT", fmt, option, reply);
  405.     else
  406.         printoption("<SENT", fmt, option, reply);
  407. }
  408.  
  409. void dooption(short option, cnr *cp)
  410. {
  411.     unsigned char *fmt;
  412.  
  413.     switch (option) {
  414.  
  415.     case TELOPT_TM:
  416.         fmt = will;
  417.         break;
  418.  
  419.     case TELOPT_EOR:
  420.     case TELOPT_BINARY:
  421.     case TELOPT_TTYPE:        /* terminal type option */
  422.     case TELOPT_SGA:        /* no big deal */
  423.     case TELOPT_3270:        /* what we're here for */
  424.         fmt = will;
  425.         (cp->myopts)[option] = 1;
  426.         break;
  427.  
  428.     case TELOPT_ECHO:        /* We're never going to echo... */
  429.     default:
  430.         fmt = wont;
  431.         break;
  432.     }
  433.     sprintf(cp->replyptr, fmt, option);
  434.     cp->replyptr += sizeof (doopt) - 2;
  435.     printoption(">SENT", fmt, option, 0);
  436. }
  437.  
  438. /*
  439.  * suboption(cnr *cp)
  440.  *
  441.  *    Look at the sub-option buffer, and try to be helpful to the other
  442.  * side.
  443.  *
  444.  *    Currently we recognize:
  445.  *
  446.  *        Terminal type, send request.
  447.  */
  448.  
  449. void suboption(cnr *cp)
  450. {
  451. unsigned char * usertype;
  452. short usersize;
  453.  
  454.     printsub("<", cp->subbuffer, cp->subend-cp->subbuffer+1);
  455.     switch (cp->subbuffer[0]&0xff) {
  456.         case TELOPT_TTYPE:
  457.             if ((cp->subbuffer[1]&0xff) == TELQUAL_SEND) {
  458.                 /* check for a specific type the user specified after
  459.                    the host name. */
  460.                 usertype = cp->connhostname;
  461.                 while ((*usertype != '\0') && (*usertype != ':')) usertype++;
  462.                 if (*usertype == ':') {
  463.                     usertype++;
  464.                     usersize = 0;
  465.                     while ((usertype[usersize] != '\0') &&
  466.                            (usertype[usersize] != ':')) usersize++;
  467.                     if (usersize > 0) {
  468.                         memcpy(cp->replyptr, sb_terminal, 4);
  469.                         memcpy(cp->replyptr+4, usertype, usersize);
  470.                         memcpy(cp->replyptr+4+usersize, sb_terminal+14, 2);
  471.                         printsub(">", cp->replyptr+2, 4+usersize);
  472.                         cp->replyptr += usersize + 6;
  473.                         if (strncmp(usertype, "IBM-327", 7) == 0)
  474.                             cp->sent3270tt = 1;
  475.                         return;
  476.                         }
  477.                     }
  478.  
  479.                 /*
  480.                 * Try to send a 3270 type terminal name.  Decide which one based
  481.                  * on the format of our screen, color capabilities, whether
  482.                  * we should support extended data streams, and whether we are
  483.                 * sending the first or a subsequent terminal name.
  484.                  */
  485.  
  486.                 /* Use 3278 unless color is available.
  487.                    With color, use 3279 unless extended datastream support
  488.                    is not wanted (cp->cs.ext3270 = 0) and we already tried sending
  489.                    3279 previously (cp->sent3270tt = 1)                         */
  490.  
  491.                 if (colormac && (!cp->cs.nocolor) && !((!cp->cs.ext3270)
  492.                              && cp->sent3270tt)) {
  493.                     sb_terminal[SBTERMTYPE] = '9';
  494.                     sb_e_terminal[SBTERMTYPE] = '9';
  495.                     }
  496.                 else {
  497.                     sb_terminal[SBTERMTYPE] = '8';
  498.                     sb_e_terminal[SBTERMTYPE] = '8';
  499.                     }
  500.                     
  501.                 /* set model number */
  502.                 
  503.                 sb_terminal[SBTERMMODEL] = 
  504.                                 getmodel(cp->cs.altrows, cp->cs.altcols, cp) & 0x0f;
  505.                 sb_terminal[SBTERMMODEL] += 0x30;
  506.                 sb_e_terminal[SBTERMMODEL] = sb_terminal[SBTERMMODEL];
  507.                 
  508.                 /* For model 4 and 5, always use 3278, since there are no
  509.                    real 3279-4 and 3279-5 terminals.  The VM logical device
  510.                    facility rejects 3279-4 and 3279-5, even though VM TCP/IP
  511.                    accepts them (yes, it's a bug). */
  512.  
  513.                  if ((sb_terminal[SBTERMMODEL] == '4') ||
  514.                       (sb_terminal[SBTERMMODEL] == '5')) {
  515.                     sb_e_terminal[SBTERMTYPE] = sb_terminal[SBTERMTYPE] ='8';
  516.                     }
  517.  
  518.                 /* Append "-E" to terminal type unless extended datastream
  519.                    support is not wanted (cp->cs.ext3270 = 0) or a previous
  520.                    terminal type ending with "-E" was possibly rejected 
  521.                    (cp->sent3270tt = 1).                                        */
  522.                    
  523.                 if (cp->cs.ext3270 && (!cp->sent3270tt)) {
  524.                     memcpy(cp->replyptr, sb_e_terminal, sizeof(sb_e_terminal));
  525.                     printsub(">", cp->replyptr+2, sizeof(sb_e_terminal)-2);
  526.                     cp->replyptr += sizeof(sb_e_terminal);
  527.                     }
  528.                 else {
  529.                     memcpy(cp->replyptr, sb_terminal, sizeof(sb_terminal));
  530.                     printsub(">", cp->replyptr+2, sizeof(sb_terminal)-2);
  531.                     cp->replyptr += sizeof(sb_terminal);
  532.                     }
  533.  
  534.                 cp->sent3270tt = 1;
  535.                 return;
  536.                 }
  537.     default:
  538.             break;
  539.     }
  540. }
  541.  
  542. void SetIn3270(cnr *cp)
  543. {
  544. char do3270;
  545.  
  546.     cp->data_init = 1;        /* reset data flag after negotiation */
  547.  
  548.     if (!(cp->newserver)) {
  549.         cp->newserver = ((cp->myopts)[TELOPT_3270] != 0) ||
  550.                     ((cp->hisopts)[TELOPT_3270] != 0);
  551.         }
  552.  
  553.     if (cp->newserver) {
  554.         do3270 = ((cp->myopts)[TELOPT_3270] /* && (cp->hisopts)[TELOPT_3270] */);
  555.         }
  556.     else {
  557.         do3270 = (cp->sent3270tt && (cp->myopts)[TELOPT_BINARY]
  558.                 && (cp->hisopts)[TELOPT_BINARY] /* && !donebinarytoggle */);
  559.         }
  560.  
  561.     if (do3270) {
  562.         if (!(cp->logon)) {
  563.             cp->showfkey = 1;        /* enable fkey menu */
  564.             appl_menu();
  565.             cp->connstate = 5;
  566.             cp->logon = 1;
  567.             newstat(cp);
  568.             }
  569.         }
  570.     else {
  571.         if (cp->logon) {
  572.             cp->hadascii = 1;
  573.             cp->connstate = 4;
  574.             cp->logon = 0;
  575.             cp->skiplf = cp->escmode = 0;
  576.             cp->showfkey = 0;        /* disable fkey menu */
  577.             appl_menu();
  578.             cp->kblock = cp->aplmode = cp->insmode = 0;
  579.             cp->fixbracket = cp->cs.std_brack && (!(cp->aplmode)) &&
  580.                              (cp->stdfont != ALAFONT);
  581.             cp->kblcode = 0;
  582.             cp->fsinv = 0;
  583.             newstat(cp);
  584.             clrscn(cp);
  585.             invldscr(cp);
  586.             }
  587.         }
  588. }
  589.  
  590. void printsub(unsigned char *direction,        /* "<" or ">" */
  591.               unsigned char *pointer,        /* where suboption data sits */
  592.               short length)                    /* length of suboption data */
  593. {
  594.     if (cf_dblevel) {
  595.     sprintf(dbgmsg, "%s suboption ",
  596.                 (direction[0] == '<')? "Received":"Sent");
  597.     putln(dbgmsg);
  598.     switch (pointer[0]) {
  599.     case TELOPT_TTYPE:
  600.         sprintf(dbgmsg, "Terminal type ");
  601.         putln(dbgmsg);
  602.         switch (pointer[1]) {
  603.         case TELQUAL_IS:
  604.         {
  605.             unsigned char tmpbuf[/*sizeof(cp->subbuffer)*/ 100];
  606.             short minlen;
  607.  
  608.             if (length > 3) length -= 3;
  609.             if (length < sizeof(tmpbuf)) minlen = length;
  610.             else minlen = sizeof(tmpbuf);
  611.  
  612.              memcpy(tmpbuf, pointer+2, minlen);
  613.             tmpbuf[minlen-1] = 0;
  614.             sprintf(dbgmsg, "is %s.\n", tmpbuf);
  615.             putln(dbgmsg);
  616.         }
  617.         break;
  618.         case TELQUAL_SEND:
  619.         sprintf(dbgmsg, "- request to send.\n");
  620.         putln(dbgmsg);
  621.         break;
  622.         default:
  623.         sprintf(dbgmsg,
  624.                 "- unknown qualifier %d (0x%x).\n", pointer[1]);
  625.         putln(dbgmsg);
  626.         }
  627.         break;
  628.     default:
  629.         sprintf(dbgmsg, "Unknown option %d (0x%x)\n",
  630.                     pointer[0], pointer[0]);
  631.         putln(dbgmsg);
  632.     }
  633.     }
  634. }
  635.  
  636. void tcpdata(unsigned char *sptr, short slen,
  637.              char init, char end, cnr *cp)
  638. {
  639. short wsflen;
  640. unsigned char * dataptr;
  641. short datalen;
  642. char winit;
  643.  
  644. if (cf_dblevel > 2) {
  645.     sprintf(dbgmsg, "tcpdata: len = %d, init = %d, end = %d",
  646.                     slen, init, end);
  647.     putln(dbgmsg);
  648.     }
  649.  
  650. if (cp->apiopenpend) {
  651.     apiregister(1, cp);            /* register session */
  652.     if (!(cp->logon)) {
  653.         apiopenresp(openLineMode, cp);
  654.         }
  655.     else {
  656.         apiopenresp(open3270Mode, cp);
  657.         }
  658.     }
  659.     
  660. if (!(cp->logon)) {
  661.     if (cp->kblock) {
  662.         cp->kblock = 0;
  663.         newstat(cp);
  664.         }
  665.     cp->hadascii = 1;
  666.     if (cp->servermode) putsrv(sptr, slen, 0, cp);
  667.     else putscr(sptr, slen, 0, cp);
  668.     writeresponse(0, cp);
  669.     return;
  670.     }
  671.  
  672. /* length 0 valid only if init==0 and end==1 */
  673. if ((slen == 0) && (init || (!end))) return;
  674.  
  675. if (init) {
  676.     cp->wsfflag = ((sptr[0] == 0x11) || (sptr[0] == 0xf3)); 
  677.     if (cp->wsfflag) {
  678.         cp->wsfptr = cp->wsfbuff;
  679.         cp->wsfleft = 8192;
  680.         cp->wsfop = sptr[0];
  681.         }
  682.     }
  683.  
  684. if (cp->wsfflag) {
  685.     if (slen > 0) {
  686.         if (slen > cp->wsfleft) wsflen = cp->wsfleft;
  687.         else wsflen = slen;
  688.         memcpy(cp->wsfptr, sptr, wsflen);
  689.         cp->wsfleft -= wsflen;
  690.         cp->wsfptr += wsflen;
  691.         }
  692.     if (end) { 
  693.         /* invldscr(); */
  694.         if (cp->cs.dblevel > 1) dbgdump("writesf", cp->wsfbuff,
  695.             cp->wsfptr-cp->wsfbuff);
  696.         writesf(cp->wsfbuff, cp->wsfptr-cp->wsfbuff, 1, cp);
  697.         writeresponse(cp->wsfop, cp);
  698.         }
  699.     return;
  700.     }
  701.  
  702. if (init) {
  703.     cp->lstopcd = sptr[0];
  704.     cp->xtralen =  cp->xtrainit = 0;
  705.     cp->needtoend = 0;
  706.     }
  707.  
  708. switch (cp->lstopcd) {
  709.     case 0x01:                    /* write */
  710.     case 0x05:                    /* erase/write */
  711.     case 0x0d:                    /* erase/write alt. */
  712.     case 0xf1:                    /* SNA write */
  713.     case 0xf5:                    /* SNA erase/write */
  714.     case 0x7e:                    /* SNA erase/write alt. */
  715.             if (init && (slen == 1)) {        /* just op-code */
  716.                 cp->xtralen = 1;            /* save op-code until wcc */
  717.                 cp->xtradata[0] = sptr[0];
  718.                 cp->xtrainit = 1;
  719.                 break;
  720.                 }
  721.             if (slen > 0) {
  722.                 cp->needtoend = 1;
  723.                 if (cp->xtralen > 0)
  724.                     memcpy(sptr-cp->xtralen, cp->xtradata, cp->xtralen);
  725.                 cp->ldvoff = 0;
  726.                 dataptr = sptr-cp->xtralen;
  727.                 datalen = slen + cp->xtralen;
  728.                 if (cp->xtrainit) winit = 1;
  729.                 else winit = init;
  730.                 if (cp->cs.dblevel > 1) {
  731.                     sprintf(dbgmsg, "writetm: init = %d", winit);
  732.                     dbgdump(dbgmsg, dataptr, datalen);
  733.                     }
  734.                 writetm(dataptr, datalen, winit, cp);
  735.                 cp->xtralen = datalen - cp->ldvoff;
  736.                 cp->xtrainit = 0;
  737.                 if (cp->xtralen == 0) break;
  738.                 if (cp->xtralen > 64) cp->xtralen = 64;
  739.                 memcpy(cp->xtradata, dataptr+cp->ldvoff, cp->xtralen);
  740.                 }
  741.             break;
  742.     case 0x0f:                    /* erase all unprot. */
  743.     case 0x6f:                    /* SNA erase all unprot. */
  744.             if (!init) return;
  745.             funckey(10, 0, cp);
  746.             cp->rdaid = 60;
  747.             writeresponse(cp->lstopcd, cp);
  748.             return;
  749.     case 0x06:                    /* read modified */
  750.     case 0xf6:                    /* SNA read modified */
  751.             if (!init) return;
  752.             rdmcmd(cp->rdaid, cp);
  753.             writeresponse(cp->lstopcd, cp);
  754.             return;
  755.     case 0x6e:                    /* SNA read modified all */
  756.             if (!init) return;
  757.             rdmacmd(cp->rdaid, cp);
  758.             writeresponse(cp->lstopcd, cp);
  759.             return;
  760.     case 0x02:                    /* read buffer */
  761.     case 0xf2:                    /* SNA read buffer */
  762.             if (!init) return;
  763.             rdbuff(cp);
  764.             writeresponse(cp->lstopcd, cp);
  765.             return;
  766.     default:
  767.             return;
  768.     }
  769.  
  770. if (end) {
  771.     if (cp->needtoend) {
  772.         endwcc(cp);        /* sets pndbeep if beep needed */
  773.         writeresponse(cp->lstopcd, cp);
  774.         cp->needtoend = 0;
  775.         }
  776.     cp->fsinv = 1;        /* tcpevent will call invldscr and possibly beep */
  777.     }
  778. }
  779.  
  780. void tcpkbin(unsigned char asc, unsigned char chr,
  781.              unsigned char shift, cnr *cp)    
  782. {                                /* handle new character in line mode */
  783. #pragma unused(shift)
  784.  
  785. static unsigned char nl[2] = {0x0d, 0x0a};
  786. static unsigned char brk[2] = {0xff, 0xf3};
  787. static unsigned char del[2] = {0xff, 0xf7};
  788. static unsigned char up[2] = {0x1b, 0x41};
  789. static unsigned char down[2] = {0x1b, 0x42};
  790. static unsigned char right[2] = {0x1b, 0x43};
  791. static unsigned char left[2] = {0x1b, 0x44};
  792. static unsigned char pf1[3] = {0x1b, 0x4f, 0x50};
  793. static unsigned char pf2[3] = {0x1b, 0x4f, 0x51};
  794. static unsigned char pf3[3] = {0x1b, 0x4f, 0x52};
  795. static unsigned char pf4[3] = {0x1b, 0x4f, 0x53};
  796. unsigned char c;
  797.  
  798. switch(chr) {        /* Note: keyboard event processing code must be
  799.                              updated if this list of functions is changed.    */
  800.     case 190:                /* "rub-out" function */
  801.         tcpwrite(del, 2, cp);
  802.         break;
  803.     case 170:                /* "clear" function */
  804.         tcpwrite(brk, 2, cp);
  805.         break;
  806.     case 142:                /* "enter" function */
  807.         tcpwrite(nl, 2, cp);
  808.         break;
  809.     case 175:                /* "left" function */
  810.         c = 0x08;                /* send normal backspace */
  811.         tcpwrite(&c, 1, cp);
  812.         break;
  813.     case 143:                /* "pf1" function */
  814.         tcpwrite(pf1, 3, cp);
  815.         break;
  816.     case 144:                /* "pf2" function */
  817.         tcpwrite(pf2, 3, cp);
  818.         break;
  819.     case 145:                /* "pf3" function */
  820.         tcpwrite(pf3, 3, cp);
  821.         break;
  822.     case 146:                /* "pf4" function */
  823.         tcpwrite(pf4, 3, cp);
  824.         break;
  825.     case 173:                /* "up" function */
  826.         tcpwrite(up, 2, cp);
  827.         break;
  828.     case 174:                /* "down" function */
  829.         tcpwrite(down, 2, cp);
  830.         break;
  831.     case 184:                /* "delete-char" function */
  832.         tcpwrite(left, 2, cp);
  833.         break;
  834.     case 176:                /* "right" function */
  835.         tcpwrite(right, 2, cp);
  836.         break;
  837.     default:
  838.         if (asc > 127) return;
  839.         c = asc;
  840.         tcpwrite(&c, 1, cp);
  841.         break;
  842.     }
  843. }
  844.